from tkinter import *
from tkinter import messagebox
import tkinter
from tkinter import ttk
from tkinter.tix import Tk, Control, ComboBox
import socket
import string

root= tkinter.Tk()
root.title('UDP校验和计算')
root.geometry('500x500')

#计算长度
def checklen():
     z=en1.get()
     l=int(len(z)/2)+8
     en11.delete(0,END)
     en14.delete(0,END)
     en11.insert(END,l)
     en14.insert(END,l)
     
#校验和计算
def checksum():
     a = []
     s1 = en1.get()  #获取数据部分的值
     if len(s1)%4 == 0:
          a.append(s1)
     else:
          s1=s1+'00' #数据部分长度为奇数时补零
          a.append(s1)
     
     s2 = en2.get() #获取源IP地址（en2）的值
     if s2.isdigit(): #判断字符串是否只由数字组成
          s2 = int(s2,10)
          if (s2>=0)&(s2<=255): #判断s2是否在[0，255]之间
               s2 = hex(s2)[2:].zfill(2) #转十六进制
               a.append(s2)
          else: #输入数字范围错误时弹出提示
               messagebox.showinfo('提示','请输入0-255的数字')
               en2.delete(0,END) #清空该框中输入错误的数
     else: #输入的不只是数字时弹出提示
          messagebox.showinfo('提示','请输入0-255的数字')
          en2.delete(0,END) #清空该框中输入错误的数
     
     
     s3 = en3.get() #获取源IP地址（en3）的值
     if s3.isdigit():  #判断字符串是否只由数字组成
          s3 = int(s3,10)
          if (s3>=0)&(s3<=255): #判断s2是否在[0，255]之间
               s3 = hex(s3)[2:].zfill(2)
               a.append(s3)
          else: #输入数字范围错误时弹出提示
               messagebox.showinfo('提示','请输入0-255的数字')
               en3.delete(0,END)#清空该框中输入错误的数
     else: #输入的不只是数字时弹出提示
          messagebox.showinfo('提示','请输入0-255的数字')
          en3.delete(0,END)   #清空该框中输入错误的数

     s4 = en4.get() #获取源IP地址（en4）的值
     if s4.isdigit():
          s4 = int(s4,10)
          if (s4>=0)&(s4<=255):
               s4 = hex(s4)[2:].zfill(2)
               a.append(s4)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en4.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en4.delete(0,END)

     s5 = en5.get() #获取源IP地址（en5）的值
     if s5.isdigit():
          s5 = int(s5,10)
          if (s5>=0)&(s5<=255):
               s5 = hex(s5)[2:].zfill(2)
               a.append(s5)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en5.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en5.delete(0,END)

     s6 = en6.get() #获取目的IP地址（en6）的值
     if s6.isdigit():
          s6 = int(s6,10)
          if (s6>=0)&(s6<=255):
               s6 = hex(s6)[2:].zfill(2)
               a.append(s6)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en6.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en6.delete(0,END)
     
     s7 = en7.get() #获取目的IP地址（en7）的值
     if s7.isdigit():
          s7 = int(s7,10)
          if (s7>=0)&(s7<=255):
               s7 = hex(s7)[2:].zfill(2)
               a.append(s7)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en7.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en7.delete(0,END)
     
     s8 = en8.get() #获取目的IP地址（en8）的值
     if s8.isdigit():
          s8 = int(s8,10)
          if (s8>=0)&(s8<=255):
               s8 = hex(s8)[2:].zfill(2)
               a.append(s8)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en8.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en8.delete(0,END)

     s9 = en9.get() #获取目的IP地址（en9）的值
     if s9.isdigit():
          s9 = int(s9,10)
          if (s9>=0)&(s9<=255):
               s9 = hex(s9)[2:].zfill(2)
               a.append(s9)
          else:
               messagebox.showinfo('提示','请输入0-255的数字')
               en9.delete(0,END)
     else:
          messagebox.showinfo('提示','请输入0-255的数字')
          en9.delete(0,END)
     
     s10 = '00'
     a.append(s10)
     
     s11 = cb2.get() #获取协议的值
     x=0
     if s11 =='UDP':x=17
     x=hex(x)[2:]
     a.append(x)
     
     s12 = en11.get() #获取长度的值
     if s12.isdigit():
          s12 = hex(int(s12,10))[2:].zfill(4)
          a.append(s12)
     else: #输入的不只是数字时弹出提示
          messagebox.showinfo('提示','请输入数字')
          en11.delete(0,END)
     
     s13 = en12.get() #获取源端口号的值
     if s13.isdigit():
          s13 = hex(int(s13,10))[2:].zfill(4)
          a.append(s13)
     else:
          messagebox.showinfo('提示','请输入数字')
          en12.delete(0,END)
     
     s14 = en13.get() #获取目的端口号的值
     if s14.isdigit():
          s14 = hex(int(s14,10))[2:].zfill(4)
          a.append(s14)
     else:
          messagebox.showinfo('提示','请输入数字')
          en13.delete(0,END)
     
     s15 = en14.get() #获取长度的值
     if s15.isdigit():
          s15 = hex(int(s15,10))[2:].zfill(4)
          a.append(s15)
     else:
          messagebox.showinfo('提示','请输入数字')
          en14.delete(0,END)
     
     s16 = en15.get() #获取校验和的值，初始输入为0
     if s16.isdigit():
          s16 = hex(int(s16,10))[2:].zfill(4)
          a.append(s16)
     else:
          messagebox.showinfo('提示','请输入数字')
          en15.delete(0,END)

     c=[]
     c = ''.join(a) #字符串合并
     
     b =[] 
     j=0
     k=int(len(c) / 4)
     for i in range(0,k):
         m = c[j:j+4]  #每16bit为一组
         b.append(m)
         j=j+4

     sum =0
     for i in b:
         sum = int(i,16)+sum  #相加求和
     #若溢出，将高16位与低16位相加，和取反
     sum = 0xffff-((0x0000ffff&sum)+(sum>>16))
     sum = hex(sum)  #校验和结果用十六进制显示
     #用Label显示校验和结果
     labe16=Label(root,text=sum,justify=RIGHT,width=70,bg='white')
     labe16.place(x=200, y=310, relwidth=0.4, relheight=0.05)
     en16.delete(0,END)
     en16.insert(0,sum)


#发包
def send():
    s = en1.get()
    s1 = en2.get()
    s2 = en3.get()
    s3 = en4.get()
    s4 = en5.get()
    s5 = en6.get()
    s6 = en7.get()
    s7 = en8.get()
    s8 = en9.get()
    s9 = '0'
    s10 = cb2.get()
    s11 = en11.get()
    s12 = en12.get()
    s13 = en13.get()
    s14 = en14.get()
    s15 = en15.get()
    s16 = en16.get()
    
    d1='UDP数据：'+s+'   '
    d2='源IP地址：'+s1+'.'+s2+'.'+s3+'.'+s4+'   '
    d3='目的IP地址：'+s5+'.'+s6+'.'+s7+'.'+s8+'   '
    d5=s9+'   '
    d4='协议：'+s10+'   '
    d5='长度：'+s11+'   '
    d6='源端口号：'+s12+'   '
    d7='目的端口号：'+s13+'   '
    d8='长度'+s14+'   '
    d9='校验和：'+s16
    
    d='“'+d1+d2+d3+d4+d5+d6+d7+d8+d9+'”'
    #print(d)

    sc=socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
    sc.sendto(d.encode(),('***.***.**.*',8001))
    #'***.***.**.*'里输入接收主机ip地址

     
#写入txt文档
def write():
    f = open(r'C:\Users\ADMIN\Desktop\udp\data.txt','a+')
    s = en1.get()
    s1 = en2.get()
    s2 = en3.get()
    s3 = en4.get()
    s4 = en5.get()
    s5 = en6.get()
    s6 = en7.get()
    s7 = en8.get()
    s8 = en9.get()
    s9 = '0'
    s10 = cb2.get()
    s11 = en11.get()
    s12 = en12.get()
    s13 = en13.get()
    s14 = en14.get()
    s15 = en15.get()
    s16 = en16.get()
    
    f.write('UDP数据：'+s+'\n')
    f.write('源IP地址：'+s1+'.')
    f.write(s2+'.')
    f.write(s3+'.')
    f.write(s4+'\n')
    f.write('目的IP地址：'+s5+'.')
    f.write(s6+'.')
    f.write(s7+'.')
    f.write(s8+'\n')
    f.write(s9+'    ')
    f.write('协议：'+s10+'    ')
    f.write('长度：'+s11+'\n')
    f.write('源端口号：'+s12+'    ')
    f.write('目的端口号：'+s13+'\n')
    f.write('长度'+s14+'    ')
    f.write('校验和：'+s15+'\n')
    f.write('校验和：'+s16+'\n')
    f.write('*****************************************\n')
    f.close


def qk1(event):
    en1.delete(0,END)
def qk2(event):
    en2.delete(0,END)
def qk3(event):
    en3.delete(0,END)
def qk4(event):
    en4.delete(0,END)
def qk5(event):
    en5.delete(0,END)
def qk6(event):
    en6.delete(0,END)
def qk7(event):
    en7.delete(0,END)
def qk8(event):
    en8.delete(0,END)
def qk9(event):
    en9.delete(0,END)
def qk11(event):
    en11.delete(0,END)
def qk12(event):
    en12.delete(0,END)
def qk13(event):
    en13.delete(0,END)
def qk14(event):
    en14.delete(0,END)
def qk15(event):
    en15.delete(0,END)


#定义窗体
label1=Label(root,text='请输入UDP数据部分:',justify=RIGHT,width=70)
label1.place(x=20,y=35,width=200,height=20)
en1 = Entry(root,textvariable = StringVar(value='          请输入UDP数据'))
en1.bind('<Button-1>',qk1)
en1.place(x=200, y=35, relwidth=0.4, relheight=0.05)

label2=Label(root,text='请输入UDP伪首部:',justify=RIGHT,width=70)
label2.place(x=20,y=105,width=200,height=20)
en2 = Entry(root,textvariable = StringVar(value='源'))
en2.bind('<Button-1>',qk2)
en2.place(x=200, y=105, width=42.5,height=25)
en3 = Entry(root,textvariable = StringVar(value='IP'))
en3.bind('<Button-1>',qk3)
en3.place(x=250, y=105, width=42.5, height=25)
en4 = Entry(root,textvariable = StringVar(value='地'))
en4.bind('<Button-1>',qk4)
en4.place(x=300, y=105, width=42.5, height=25)
en5 = Entry(root,textvariable = StringVar(value='址'))
en5.bind('<Button-1>',qk5)
en5.place(x=350, y=105, width=42.5, height=25)
en6 = Entry(root,textvariable = StringVar(value='目的'))
en6.bind('<Button-1>',qk6)
en6.place(x=200, y=135, width=42.5, height=25)
en7 = Entry(root,textvariable = StringVar(value='IP'))
en7.bind('<Button-1>',qk7)
en7.place(x=250, y=135, width=42.5, height=25)
en8 = Entry(root,textvariable = StringVar(value='地'))
en8.bind('<Button-1>',qk8)
en8.place(x=300, y=135, width=42.5, height=25)
en9 = Entry(root,textvariable = StringVar(value='址'))
en9.bind('<Button-1>',qk9)
en9.place(x=350, y=135, width=42.5, height=25)
labe10=Label(root,text='0',justify=RIGHT,width=70,bg='white')
labe10.place(x=200,y=165,width=25,height=25)
comvalue2=tkinter.StringVar()#窗体自带的文本，新建一个值
cb2=ttk.Combobox(root,textvariable=comvalue2,state= 'readonly') #初始化
cb2["values"]=('协议','UDP')
cb2.current(0) #选择第一个
cb2.pack()
cb2.place(x=235,y=165, relwidth=0.1, relheight=0.05)
en11 = Entry(root,textvariable = StringVar(value='长度'))
en11.bind('<Button-1>',qk11)
en11.place(x=295, y=165, width=55, height=25)

label3=Label(root,text='请输入UDP首部:',justify=RIGHT,width=70)
label3.place(x=20,y=210,width=210,height=20)
en12 = Entry(root,textvariable = StringVar(value='源端口号'))
en12.bind('<Button-1>',qk12)
en12.place(x=200, y=210, width=85, height=25)
en13 = Entry(root,textvariable = StringVar(value='目的端口号'))
en13.bind('<Button-1>',qk13)
en13.place(x=295, y=210, width=105, height=25)
en14 = Entry(root,textvariable = StringVar(value='长度'))
en14.bind('<Button-1>',qk14)
en14.place(x=200, y=240, width=85, height=25)
en15 = Entry(root,textvariable = StringVar(value='校验和'))
en15.bind('<Button-1>',qk15)
en15.place(x=295, y=240, width=105, height=25)


label4=Label(root,text='校验和:',justify=RIGHT,width=70)
label4.place(x=10,y=310,width=210,height=20)
en16 = Entry(root,textvariable = StringVar(value=''))
en16.place(x=200, y=310, relwidth=0.4, relheight=0.05)

labe16=Label(root,text="",justify=RIGHT,width=70,bg='white')
labe16.place(x=200, y=310, relwidth=0.4, relheight=0.05)


btn1 = Button(root, text='校验',command=checksum)
btn1.place(x=100, y=400, relwidth=0.15, relheight=0.05)
btn2 = Button(root, text='发送',command=send)
btn2.place(x=200, y=400, relwidth=0.15, relheight=0.05)
btn3 = Button(root, text='记录',command=write)
btn3.place(x=300, y=400, relwidth=0.15, relheight=0.05)
btn4 = Button(root, text='计算',command=checklen)
btn4.place(x=355, y=165, relwidth=0.08, relheight=0.05)

mainloop()
